#ifndef BSW_XARRAY_H
#define BSW_XARRAY_H

#include "bsw_pageca.h"
#include "bsw_auto_lock.h"

typedef uint64_t bsw_xy_leaf_t;
typedef int (*bsw_xy_lock_f)(bsw_lock_rw_t *);
typedef enum   bsw_xy_type  bsw_xy_type_e;
typedef struct bsw_xarray   bsw_xarray_s;
typedef struct bsw_xy_node  bsw_xy_node_s;
typedef struct bsw_xy_state bsw_xy_state_s;

#if 0
#endif
enum bsw_xy_type {
    BSW_XY_CACHE_NONE,
    BSW_XY_CACHE_FULL,
    BSW_XY_CACHE_MAX
};

/**
 * xarray 头信息
 * head 指向头结点
 *  [63] 预分配
 *  [62] 动态分配
 *  [61..0] 顶层结点
 * lock 锁保护
 * ca  结点预分配
 *  [0] 中间结点预分配
 *  [1] 叶子结点预分配
 */
struct bsw_xarray {
    uint64_t head;
    bsw_lock_rw_t lock;
    bsw_pageca_s ca[];
};

/**
 * 根据实际场景修改
 * BSW_XY_SLOTS XY_LEVEL_EXP 如
 * 2  1
 * 4  2
 * 8  3
 * 16 4
 * 32 5
 * 64 6
 * 再扩展可能需要适配下诸如
 * xy_node.s_value 相关代码
 */
#define BSW_XY_SLOTS    (16)
/**
 * xarray 结点信息
 * slot   槽位指针数组
 * parent 父结点指针
 * 
 * n_idx 结点在父结点中的槽位
 * s_use 结点槽位使用数
 * l_exp 结点层级幂
 * s_value 叶子结点槽位使用标识
 */
struct bsw_xy_node {
    bsw_xy_node_s *slot[BSW_XY_SLOTS];
    bsw_xy_node_s *parent;

    uint32_t n_idx:8;
    uint32_t s_use:8;
    uint32_t l_exp:8;
    bsw_xy_leaf_t s_value[];
};

/**
 * xarray 访问辅助结构
 * error 错误值
 *
 * xy 欲访问的 xarray
 * x  欲操作索引；遍历时存最小值
 *
 * node     当前操作结点
 * x_ranged 遍历时是否已指定范围
 * y_null   范围遍历时是否返回中途所遇空值
 * s_idx    索引 x 在当前结点槽位
 * 
 * x_max 用于遍历时存最大索引
 * t_max_ns   xarray连续运行最大时间
 * t_sleep_ns 连续运行后休休眠时间
 */
struct bsw_xy_state {
    int error;

    bsw_xarray_s *xy;
    uint64_t x;

    bsw_xy_node_s *node;
    bool     x_ranged;
    unsigned y_null:1;
    unsigned s_idx:8;

    uint64_t x_max;
    uint64_t t_max_ns;
    uint64_t t_sleep_ns;
};
#define bsw_xys_error(xs)        ({(xs)->error;})
#define bsw_xys_error_set(xs, e) ({(xs)->error=e;})

/**
 * 初始化 xarray @xy
 * 若 @xy 为 NULL 则分配 xarray 实例初始化后将其返回；
 * 否则直接初始化 @xy 后将其返回；失败返 NULL。
 * 
 * 当 @flag=BSW_XY_CACHE_NONE 时
 * 无内存预分配；
 * 
 * 当 @flag=BSW_XY_CACHE_FULL 时
 * 将 @ca[63..0] 视为最大索引值，依此为叶子结点和中间结点
 * 预分配内存；
 * 
 * 当 @flag=BSW_XY_CACHE_MAX 时
 * 叶子结点预分配 @ca[31..0]，中间结点预分配 @[63..32]
 */
bsw_xarray_s * 
bsw_xy_init(bsw_xarray_s *xy, unsigned flag, uint64_t ca);

/**
 * 释放 xarray @xy 中的内存资源
 */
void bsw_xy_close(bsw_xarray_s *xy);

/**
 * 在 xarray @xs->xy 中
 * 根据索引 @xs->x 新增目标值 @y，
 * 
 * 当索引 @xs->x 已映射目标值，目标值 @y 覆盖
 * 旧目标值并返回旧目标值；否则返回新目标值 @y。
 * 
 * 当映射目标值 @y 失败时，xs->error 为负数。
 */
void * bsw_xys_add(bsw_xy_state_s *xs, void *y);

/**
 * 在 xarray @xs->xy 中,
 * 当 @xs->x_ranged=1 时，遍历索引范围 
 * [xs->x, xs->x_max] 对应目标值；
 *
 * 当 @xs->x_ranged=0 时，先查询索引范围
 * [xs->x, xs->x_max], 再遍历对应目标值；
 * 
 * 当 @xs->y_null=1 时，索引无目标值时亦
 * 返回，否则会遍历到一个有效目标值为止；
 * 
 * 当 @xs->t_max_ns 和 @xs->t_sleep_ns
 * 皆不为 0 时，持续遍历时间超 @xs->t_max_ns
 * 后会释放锁并睡眠 @xs->t_max_ns 时间。
 */
void * bsw_xys_foreach(bsw_xy_state_s *xs);

/**
 * 在 xarray @xs->xy 中查询索引 @xs->x
 * 对应目标值。
 */
void * bsw_xys_get(bsw_xy_state_s *xs);

/**
 * 在 xarray @xs->xy 中删除索引 @xs->x
 * 对应目标值。
 */
void * bsw_xys_del(bsw_xy_state_s *xs);

#endif